package edu.ccut.saturn.component.impl.node;

import java.util.ArrayList;
import java.util.List;

import edu.ccut.saturn.component.ComponentManager;
import edu.ccut.saturn.component.IActionContext;
import edu.ccut.saturn.component.ILogicContext;
import edu.ccut.saturn.component.IParameterContext;
import edu.ccut.saturn.component.IParameterInfo;
import edu.ccut.saturn.component.IWebContextValueInfo;
import edu.ccut.saturn.component.SaturnDebugThreadsManager;
import edu.ccut.saturn.component.impl.SaturnActionContext;
import edu.ccut.saturn.component.impl.SaturnParameterInfo;
import edu.ccut.saturn.component.loader.node.NodeInfoLoader;
import edu.ccut.saturn.component.loader.node.WebContextNodeInfoLoader;
import edu.ccut.saturn.component.utils.ExceptionUtils;
import edu.ccut.saturn.component.xml.ISaturnElement;
import edu.ccut.saturn.component.xml.SaturnElement;

/**
 * 网页上下文结点的实现类。在action组件中被调用，这个结点是用于在logic数据域、request数据域、session数据域、application数据域
 * 间传递、或删除数据的。例如可以把logic数据域中的某个变量放到request域中或session域中；可以删除session域的某个变量。
 * <p>
 * <code>WebContextNodeInfo</code>类扩展了<code>AbstractNodeInfo</code>：
 * <li>字段<code>valueInfos</code>：记录了需要操作的上下文信息列表。具体包括把某个域的哪个变量放到另一个域的哪个变量里；
 * 要删除某个域里的哪个变量。
 * 
 * @author 温建
 * 
 * @version 1.0 2008.8.22
 * 
 * @see AbstractNodeInfo
 * @see IWebContextValueInfo
 * @see ILogicContext
 * 
 */
public class WebContextNodeInfo extends AbstractNodeInfo {
	// TODO:结点中是不是应该建立对象保存具体细节信息，还是用map等集合保存或建立内部类，不放到接口中。
	private List<IWebContextValueInfo> valueInfos = null;

	public WebContextNodeInfo(String id, String name, String description,
			String nextId, List<IParameterInfo> parameters, String x, String y) {

		super(id, name, description, nextId, parameters, x, y, "webContext");
	}

	/**
	 * 获得需要操作的上下文信息列表
	 * 
	 * @return
	 */
	public List<IWebContextValueInfo> getValueInfos() {
		return valueInfos;
	}

	/**
	 * 网页上下文结点的执行逻辑。 逐项处理需要操作的上下文信息列表中的每项记录，首先判断是否要从某个域中删除变量，是则完成删除操作。
	 * 否则进行的是变量在数据域间的传递，支持在同一数据域中不同变量的赋值操作和不同数据域间变量的传递。
	 * 
	 * @param logicContext
	 *            逻辑上下文对象，记录结点运行时的上下文信息
	 * @throws Exception
	 */
	@Override
	public void doExecute(ILogicContext logicContext) throws Exception {

		ComponentManager.beforeExecuteComponent(this,
				createParameterContext(logicContext));

		try {
			if (logicContext instanceof SaturnActionContext) {
				IActionContext actionContext = (IActionContext) logicContext;

				for (IWebContextValueInfo webContextValueInfo : valueInfos) {
					String isDelete = webContextValueInfo.getIsDelete();

					if ("true".equals(isDelete)) {
						String key = webContextValueInfo.getKey();
						String scope = webContextValueInfo.getScope();

						if (scope != null) {
							actionContext.removeParameterKey(key, Integer
									.parseInt(scope));
						}

					} else if ("false".equals(isDelete)) {
						String key = webContextValueInfo.getKey();
						String scope = webContextValueInfo.getScope();
						String newKey = webContextValueInfo.getNewKey();
						String newScope = webContextValueInfo.getNewScope();

						if (newScope != null && !newScope.equals("")) {
							Object value = actionContext.getValue(key, Integer
									.parseInt(scope));

							if (newKey != null && !newKey.equals("")) {
								actionContext.setValue(newKey, value, Integer
										.parseInt(newScope));

							} else if (!scope.equals(newScope)) {
								actionContext.setValue(key, value, Integer
										.parseInt(newScope));

							}
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("ERROR : {message :'" + ExceptionUtils.getExMessage(e) + "', process : '" + logicContext.getId() + "', node : '" +
					 super.getNodeType() + " " + super.getId() + " " + super.getName() + "'}");

			throw e;

		} finally {
			ComponentManager.afterExecuteComponent(this,
					createParameterContext(logicContext));
		}
	}

	protected IParameterContext createParameterContext(
			ILogicContext logicContext) throws Exception {

		if (SaturnDebugThreadsManager.getInstance().isStart()) {
			initParameterInfos();
			return logicContext.createParameterContext(getParameterInfos());
		}
		return null;
	}

	private void initParameterInfos() {
		int parameterIndex = 0;
		List<IParameterInfo> parameters = new ArrayList<IParameterInfo>();

		for (IWebContextValueInfo context : valueInfos) {
			parameterIndex++;
			SaturnParameterInfo inParameterInfo = new SaturnParameterInfo();
			inParameterInfo.setClassType(Object.class);
			inParameterInfo.setName("input " + String.valueOf(parameterIndex));
			inParameterInfo.setId(String.valueOf(parameterIndex));
			inParameterInfo.setValueKey(context.getKey());
			inParameterInfo.setScope(Integer.parseInt(context.getScope()));
			inParameterInfo.setPassingType(IParameterInfo.PASSING_IN);
			parameters.add(inParameterInfo);

			SaturnParameterInfo outParameterInfo = new SaturnParameterInfo();
			outParameterInfo.setClassType(Object.class);
			outParameterInfo
					.setName("output " + String.valueOf(parameterIndex));

			outParameterInfo.setId(String.valueOf(parameterIndex));

			if ("true".equals(context.getIsDelete())) {
				outParameterInfo.setValueKey(context.getKey());
				outParameterInfo.setScope(Integer.parseInt(context.getScope()));
				outParameterInfo.setPassingType(IParameterInfo.PASSING_IN_OUT);

			} else {
				outParameterInfo.setValueKey(context.getNewKey());
				outParameterInfo.setScope(Integer.parseInt(context
						.getNewScope()));

				outParameterInfo.setPassingType(IParameterInfo.PASSING_IN_OUT);
			}
			parameters.add(outParameterInfo);
		}
		super.setParameterInfos(parameters);
	}

	/**
	 * 设置需要操作的上下文信息列表
	 * 
	 * @param valueInfos
	 */
	public void setValueInfos(List<IWebContextValueInfo> valueInfos) {
		this.valueInfos = valueInfos;
	}

	public ISaturnElement toSaturnElement() {
		ISaturnElement webContextElement = new SaturnElement(
				WebContextNodeInfoLoader.KEY_WEBCONTEXT);

		webContextElement
				.addAttribute(NodeInfoLoader.KEY_NODE_ID, this.getId());

		webContextElement.addAttribute(NodeInfoLoader.KEY_NODE_NEXT, this
				.getNextId());

		webContextElement.addAttribute(NodeInfoLoader.KEY_NODE_X, this.getX());

		webContextElement.addAttribute(NodeInfoLoader.KEY_NODE_Y, this.getY());

		ISaturnElement nameElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_NAME, this.getName());

		ISaturnElement descriptionElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_DESCRIPTION, this.getDescription());

		ISaturnElement valueMovesElement = new SaturnElement(
				WebContextNodeInfoLoader.KEY_WEBCONTEXT_VALUEMOVES);

		if (this.valueInfos != null) {

			for (IWebContextValueInfo info : this.valueInfos) {
				valueMovesElement.addSubElement(info.toSaturnElement());
			}
		}
		webContextElement.addSubElement(nameElement);
		webContextElement.addSubElement(descriptionElement);
		webContextElement.addSubElement(valueMovesElement);
		return webContextElement;
	}
}
